#include "alarm.h"

#include "log.h"
#include "data.h"
#include "errcode.h"

#include <string.h>
#include <stdio.h>

struct alarm_info{
    uint8_t code;
    const char_t *alarm;
    const char_t *desc;
};

static const struct alarm_info g_alarm_info[]={
    {DC_ALARM_BUTTON, "3003", "急停按钮按下"},
    {DC_ALARM_SMOKE,  "301D", "烟感故障"},
    {DC_ALARM_AC_CIRCUIT_BREAKER,  "4000","交流输入短路故障"},
    {DC_ALARM_DC_BUS_CONTACT, "3010","直流母线输出接触器拒动/误动故障"},
        
    {DC_ALARM_DC_BUS_FUSE, "3011","直流母线输出熔断器故障"},
    {DC_ALARM_GUN_ELEC_LOCK, "3018","充电接口电子锁故障"},
    {DC_ALARM_DEV_FAN,  "3004", "充电桩风扇故障"},
    {DC_ALARM_ARRESTER, "400C","避雷器故障"},
        
    {DC_ALAEM_ISOLATION_CHECK, "500D", "绝缘监测故障"},
    {DC_ALARM_BATTERY_REVERSE, "501A", "电池极性反接故障"},
    {DC_ALARM_CHARGING_VCG, "301B", "充电中车辆控制导引故障"},
    {DC_ALARM_DEV_OVER_TEMP, "3016", "充电桩过温故障"},
        
    {DC_ALARM_GUN_OVER_TEMP, "3017", "充电接口过温故障"},
    {DC_ALARM_GUN_NOT_HOMING, "3006", "充电枪未归位告警"},
    {DC_ALARM_BMS_COMMUNICATE , "5000", "BMS通信故障"},
    {DC_ALARM_VOL_IN_OVER, "4001", "输出电压过压故障"},
        
    {DC_ALARM_VOL_IN_LOW, "4000", "输入电压欠压故障"},
    {DC_ALARM_DC_BUS_VOL_OVER, "4001", "直流母线输出过压故障"},
    {DC_ALARM_DC_BUS_VOL_LOW, "4003", "直流母线输出欠压故障"},
    {DC_ALARM_DC_BUS_CURRT_OVER, "4002", "直流母线输出过流故障"},
        
    {DC_ALARM_MOD_FAIL, "300A","充电模块故障"},
    {DC_ALARM_MOD_AC_FAIL, "4000", "充电模块交流输入故障"},
    {DC_ALARM_MOD_AC_VOL_OVER, "4000", "充电模块交流输入过压故障"},
    {DC_ALARM_MOD_AC_VOL_LOW, "4000", "充电模块交流输入欠压故障"},
        
    {DC_ALARM_MOD_AC_LOST_PHASE, "4009", "充电模块交流输入缺相故障"},
    {DC_ALARM_MOD_DC_SHORT, "4004", "充电模块直流输出短路故障"},
    {DC_ALARM_MOD_DC_CURRT_OVER, "4002", "充电模块直流输出过流故障"},
        
        
    {DC_ALARM_MOD_DC_VOL_OVER, "4001", "充电模块直流输出过压故障"},
    {DC_ALARM_MOD_DC_VOL_LOW, "4003", "充电模块直流输出欠压故障"},
    {DC_ALARM_MOD_TEMP_OVER, "300B", "充电模块过温故障"},
    {DC_ALARM_MOD_COMM_FAIL, "3008", "充电模块通信故障"},
    {DC_ALARM_MOD_FAN_FAIL, "3005", "充电模块风扇故障"},
        
    {DC_ALARM_DEV_DOOR_FAIL, "3002", "门禁故障"},
    {DC_ALARM_DC_CONTACT_ADHESION, "300F", "直流输出接触器粘连故障"},
    {DC_ALAEM_ISOLATION_CHECK0X23, "3014", "绝缘检测告警"},
        
    {DC_ALARM_RELEASE, "3015", "泄放回路故障"},
    {DC_ALARM_OVER_TEMP0X23, "3016", "充电桩过温告警"},
    {DC_ALARM_GUN_OVER_TEMP0X23, "3017", "充电枪过温告警"},
    {DC_ALARM_AC_CONTACOR0X23, "3010", "交流输入接触器据动/误动故障"},
        
    {DC_ALARM_AC_CONTACT_ADHESION0X23, "300F", "交流输入接触器粘连故障"},
    {DC_ALARM_AUX_POWER0X23, "3013", "辅助电源故障"},
    {DC_ALARM_SHUNT_CONTACT0X23, "3010", "并联接触器据动/误动故障"},
    {DC_ALARM_SHUNT_CONTACT_ADHESION0X23, "300F","并联接触器粘连故障"},

    {DC_ALARM_OTHER, "301D", "充电桩其他类型故障"},
    {DC_ALARM_ELEC_METER, "300D", "电能表通信故障"}
};

struct dc_alarm{
    uint8_t total_fault;
    uint8_t total_alarm;
    uint8_t alarm[DC_ALARM_MAX];   
    uint16_t other_alarm_code;
};

static uint8_t gunnum;
static struct dc_alarm A[2];
static alarm_notify alarm_callback = NULL;

int32_t alarm_update_total_fault(int32_t gunid, uint8_t state){
    int32_t pos = gunid-1;
    if (A[pos].total_fault != state){
        if (state == 0){
            A[pos].total_fault = state;

            //告警取消
            //log(LOG_INFO, "fault release\r\n");
        
        }else{
            A[pos].total_fault = state;

            //告警发生
            //log(LOG_INFO, "fault trigger\r\n");
        }
    }
    return 0;
}


int32_t alarm_update_total_alarm(int32_t gunid, uint8_t state){
    int32_t pos = gunid-1;
    if (A[pos].total_alarm != state){
        if (state == 0){
            A[pos].total_alarm = state;

            //告警取消
            //log(LOG_INFO, "alarm release\r\n");
        
        }else{
            A[pos].total_alarm = state;

            //告警发生
            //log(LOG_INFO, "alarm trigger\r\n");
        }
    }
    
    return 0;
}

int32_t alarm_is_emeter_alarm(int32_t gunid){
    return A[gunid-1].alarm[DC_ALARM_ELEC_METER];
}

int32_t alarm_is_fault(int32_t gunid){
    if (A[gunid-1].total_fault){
        return 1;
    }
    if (A[gunid-1].total_alarm){
        return 1;
    }
    int32_t i = 0;
    for(i=0; i<DC_ALARM_MAX; i++){
        if (A[gunid-1].alarm[i] == 0x01){
            return 1;
        }
    }
    return 0;
}

int32_t alarm_is_alarm(int32_t gunid){
    return A[gunid-1].total_alarm;
}

void alarm_all_up(void){
    int32_t i = 0;
    int32_t j = 0;
    for(i=0;i<DC_ALARM_MAX;i++){
        if (A[0].alarm[i] == 0x01){
            if (alarm_callback != NULL){
                alarm_callback(1, g_alarm_info[i].alarm, ALARM_OCCURED);
            }
            //simu_para_alarm_occured(1, g_alarm_info[i].alarm);
            j++;
        }
        if (A[1].alarm[i] == 0x01){
            if (alarm_callback != NULL){
                alarm_callback(2, g_alarm_info[i].alarm, ALARM_OCCURED);
            }
            //simu_para_alarm_occured(2, g_alarm_info[i].alarm);
            j++;
        }
    }
    if (j==0){
        if (alarm_callback != NULL){
            alarm_callback(1, ERR_CODE_SUCC, ALARM_RECOVERED);
            if (gunnum ==2 ){
                alarm_callback(2, ERR_CODE_SUCC, ALARM_RECOVERED);
            }
        }
        //simu_para_alarm_recovered(1, ERR_CODE_SUCC);
        //simu_para_alarm_recovered(2, ERR_CODE_SUCC);
    }
}

void alarm_set_other_alarm_code(int32_t gunid, uint16_t code){
    int32_t pos = gunid-1;
    A[pos].other_alarm_code = code;
}

int32_t alarm_deal(int32_t gunid, enum DC_ALARM_CODE code, uint8_t state){
    int32_t pos = gunid-1;
    if (A[pos].alarm[code] != state){
        if (state == 0){ /*告警取消*/
            A[pos].alarm[code] = state;
            log(LOG_INFO, "gun[%d]alarm %s release\r\n", gunid, g_alarm_info[code].alarm);
            alarm_log(gunid, EVENT_ALARM_OFF, code, g_alarm_info[code].desc);
            if (alarm_callback != NULL){
                alarm_callback(gunid, g_alarm_info[code].alarm, ALARM_RECOVERED);
            }   
        }else{ /*告警发生*/
            A[pos].alarm[code] = state;
            log(LOG_INFO, "gun[%d]alarm %s trigger\r\n", gunid, g_alarm_info[code].alarm);
            alarm_log(gunid, EVENT_ALARM_ON, code, g_alarm_info[code].desc);
            if (alarm_callback != NULL){
                alarm_callback(gunid, g_alarm_info[code].alarm, ALARM_OCCURED);
            }
        }
    }
    return 0;
}

void alarm_get_alarmcode(int32_t gunid, char_t *code){
    int32_t i=0;
    int32_t pos = gunid-1;
    for(i=0;i<DC_ALARM_MAX;i++){
        if (A[pos].alarm[i] == 0x01){
            strncpy(code, g_alarm_info[i].alarm, 4);
            return;
        }
    }
    strncpy(code, ERR_CODE_SUCC, 4);
}

void alarm_get_alarm_desc(int32_t gunid, char_t *code){
    int32_t i = 0;
    int32_t have_alarm = 0;
    int32_t pos = gunid-1;
    for(i=0;i<DC_ALARM_MAX;i++){
        if (A[pos].alarm[i] == 0x01){
            strcat(code, g_alarm_info[i].desc);
            if (i == DC_ALARM_OTHER){
                sprintf(code+strlen(code), "\r\n故障码:%x", A[pos].other_alarm_code);
            }
            have_alarm = 1;
            return;
        }
    }
    if (have_alarm == 0){
        strcat(code, "充电异常，请拔枪清除告警");
    }
    //printf("***********************alarm_get_alarm_desc:%s\r\n", code);
}

int32_t alarm_init(alarm_notify callback){
    memset(&A, 0, sizeof(A));
    gunnum = data_getint("gunnum");
    alarm_callback = callback;
    return 0;   
}

